package demo2

import "fmt"

/* demo1 */
// 结构体
type class struct {
	name string
}

// 给结构体添加 Do 方法
func (c *class) Do(v int) {
	fmt.Println("call method do:", v)
}

// 普通函数的 Do
func funcDo(v int) {
	fmt.Println("call function do:", v)
}

/* demo2 */

// Actor 角色
type Actor struct{}

// 为角色添加一个事件处理函数
func (a *Actor) onEvent(param interface{}) {
	fmt.Println("actor event:", param)
}

// 全局事件
func globalEvent(param interface{}) {
	fmt.Println("global event:", param)
}

// 实例化一个通过字符串映射函数切片的map
var eventByName = make(map[string][]func(interface{}))

// 注册时间，提供事件名和回调函数
func registerEvent(name string, callback func(interface{})) {
	// 通过名字查找事件列表
	list := eventByName[name]

	// 在列表切片中添加函数
	list = append(list, callback)

	// 将修改的事件列表切片保存回去
	eventByName[name] = list
}

// 调用事件
func callEvent(name string, param interface{}) {
	// 通过名字找到事件列表
	list := eventByName[name]

	// 遍历这个时间的所有回调
	for _, callback := range list {
		// 传入参数调用回调
		callback(param)
	}
}

// TestDemo214 事件系统
func TestDemo214() {
	/*
		demo1: 方法和函数的统一调用
			这段代码能运行的基础在于：无论是普通函数还是结构体的方法，
			只要它们的签名一致，与它们签名一致的函数变量就可以保存普通函数或是结构体方法。
	*/

	// 声明一个函数回调
	var delegate func(int)

	// 构建结构体实例
	c := new(class)

	// 将回调设为 c 的 Do 方法
	delegate = c.Do

	// 调用
	delegate(100)

	// 将回调设为普通函数
	delegate = funcDo

	// 调用
	delegate(200)

	/*
		demo2: 事件注册
			事件系统需要为外部提供一个注册入口。这个注册入口传入注册的事件名称和对应事件名称的响应函数，
			事件注册的过程就是将事件名称和响应函数关联并保存起来，详细实现请参考下面代码的 RegisterEvent() 函数。
	*/

	// 实例化一个角色
	actor := new(Actor)

	// 注册名为 OnSkill 的回调
	registerEvent("OnSkill", actor.onEvent)

	// 再次在 OnSkill 上注册全局事件
	registerEvent("OnSkill", globalEvent)

	// 调用事件，所有注册的同名函数都会被调用
	callEvent("OnSkill", 100)
}
